home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Fatted Calf
/
The Fatted Calf.iso
/
Modules
/
BackSpaceModules
/
Source
/
MartinView
/
MartinView.m
< prev
next >
Wrap
Text File
|
1992-11-03
|
15KB
|
588 lines
#import "MartinView.h"
#import "Thinker.h"
#import <math.h>
#import <libc.h>
#import <streams/streams.h>
#import <defaults/defaults.h>
#import <appkit/color.h>
#import <appkit/graphics.h>
#import <dpsclient/wraps.h>
#import <appkit/Button.h>
#import <appkit/Application.h>
/* MartinView: a BackSpace.app v3.0 module by Jeffrey Adams
* version 1.0 jeffa@wri.com
*/
char fname[Nfunc][16] = { "martin1", "martin2", "ejk1", "ejk2" };
/* The file used to store remembered fractals */
char fileName[] = "/.martinView";
@implementation MartinView
/* Implemented so you can screen grab the image if you want to (at least I wanted to!) */
- pause:sender
{
isPaused = [sender state];
return self;
}
/* Inherited method for setting the graphics state before sending OneSteps */
- didLockFocus
{
NXSetColor(currColor);
return self;
}
- oneStep
{
NXRect *currentPixel = pixels;
if (isPaused) return self;
/* Stay in here until we hit our flush buffer limit or we hit the maximum
total points allowed */
while ((++nd < nD) && (++nP < mxP)) {
switch (Function) {
case Ejk1: x1 = y - ( (x>0) ? (B*x-C) : -(B*x-C) ); break;
case Martin1: x1 = y - ( (x<0) ? sqrt(fabs(B*x-C)) : -sqrt(fabs(B*x-C)) ); break;
case Ejk2: x1 = y - ( (x<0) ? log(fabs(B*x-C)) : -log(fabs(B*x-C)) ); break;
case Martin2: x1 = y - sin(x); break;
}
y = A - x; x=x1;
/* seed perturbation */
if (Pn && ++pn > Pn) {
x += (x>0) ? -Pv : Pv;
y += (y>0) ? -Pv : Pv;
pn = 0;
}
/* Do we need to change the color? */
if (++nc > nC) {
color = (color+1)%Ncolors;
/* Since we are changing color, send buffered points to screen */
if (numPixels) {
NXRectFillList(pixels, numPixels);
numPixels = 0; currentPixel = pixels;
}
currColor = (Randomcolor) ? ((Color) ? NXConvertRGBToColor(Ranf(), Ranf(), Ranf()) :
NXConvertGrayToColor(Ranf())) : colors[color];
NXSetColor(currColor);
nc = 0;
}
/* If we are not within the screen range, do not store them */
iy = cy + Zf*y; if (iy < 0 || iy > mxY) continue;
ix = cx + Zf*x; if (ix < 0 || ix > mxX) continue;
/* Update the data needed for the NXRectFillList */
currentPixel->origin.x = ix; currentPixel->origin.y = iy;
++numPixels; ++currentPixel;
/* Have we hit the in-range limit, if so, send the buffer to the screen */
if (++np > mxp) {
if (numPixels) {
NXRectFillList(pixels, numPixels);
numPixels = 0; currentPixel = pixels;
}
[self newOne:self];
break;
}
}
nd = 0;
/* Flush buffer full, display pixels */
if (numPixels) {
NXRectFillList(pixels, numPixels);
numPixels = 0; currentPixel = pixels;
}
/* If we left because we hit max total limit, give us a new one */
if(nP == mxP)
[self newOne:self];
return self;
}
- newOne:sender
{
double A1, B1, C1; /* 2nd part of parameter range */
char name[15],str[20];
NXStream *stream;
int i;
[self display];
if (!smallInspect) return nil;
/* Record current settings in Defaults database */
sprintf(str,"%d", ([funcAuto state]) ? -1 : Function);
NXWriteDefault([NXApp appName], "MartinFunction", str);
sprintf(str,"%d", ([maxTotFlag state]) ? -1 : [maxTotalPts intValue]);
NXWriteDefault([NXApp appName], "MartinMaxTot", str);
sprintf(str,"%d", ([maxInFlag state]) ? -1 : [maxInRangePts intValue]);
NXWriteDefault([NXApp appName], "MartinMaxIn", str);
sprintf(str,"%d", ([colFlag state]) ? -1 : [colInterval intValue]);
NXWriteDefault([NXApp appName], "MartinColorInt", str);
np = 0; nP = 0; nd = 0; numPixels=0;
x = y = 0; color = -1;
Ranfset(time(0));
W = (int)bounds.size.width;
H = (int)bounds.size.height;
mxX = W-1; mxY = H-1;
/* If we are using a file, load the settings from '.martinView' */
if (streamPos >= 0) {
if (!(stream = NXMapFile(file, NX_READONLY))) {
streamPos = -1;
[useFileFlag setState:NO];
[self newOne:self];
return self;
}
for (i=0; i <= streamPos; ++i) {
if(NXAtEOS(stream)){
streamPos = 0; i=-1;
NXSeek(stream, 0, NX_FROMSTART);
if(NXAtEOS(stream)) {
streamPos =-1;
[useFileFlag setState:NO];
[self newOne:self];
return self;
}
continue;
}
NXScanf(stream, "%s\n",name);
NXScanf(stream, "%d %le\n",&Pn,&Pv);
NXScanf(stream, "%d\n",&Function);
NXScanf(stream, "%le %le %le %le\n",&A,&B,&C,&Zf);
NXScanf(stream, "%d %d %d\n",&mxp,&mxP,&nC);
NXScanf(stream, "%d %d\n",&moveX,&moveY);
}
streamPos++;
NXCloseMemory(stream, NX_FREEBUFFER);
}
else {
if ([seedIntFlag state]) Pn = pow(10., 1+Ranf()*3);
else Pn = [seedPertInt intValue];
if ([seedValFlag state]) Pv = pow(10.,Ranf()*3);
else Pv = [seedPertVal doubleValue];
/* provide default hopalong parameters if needed */
if ([funcAuto state]) {
double r = Ranf();
if (r < 0.40) Function = Martin1;
else if (r < 0.70) Function = Ejk1;
else if (r < 0.90) Function = Ejk2;
else Function = Martin2;
}
if (Function == Martin1) {
if ([aFlag state]) A = 40 + Ranf()*1500;
if ([bFlag state]) B = 3 + Ranf()*17;
if ([cFlag state]) C = 100 + Ranf()*3000;
}
else if (Function == Martin2) {
if ([aFlag state]) A = 3.075927 + Ranf()*0.14;
}
else if (Function == Ejk1) {
if ([aFlag state]) A = Ranf()*500;
if ([bFlag state]) B = Ranf()*.40;
if ([cFlag state]) C = 10 + Ranf()*100;
}
else if (Function == Ejk2) {
if ([aFlag state]) A = Ranf()*500;
if ([bFlag state]) B = pow(10.,6+Ranf()*24);
if ([cFlag state]) C = pow(10., Ranf()*9);
}
if(![aFlag state]) A = [hopAField doubleValue];
if(![bFlag state]) B = [hopBField doubleValue];
if(![cFlag state]) C = [hopCField doubleValue];
if (A1 = [a1Flag state]) A = Min(A,A1) + Ranf()*(Max(A,A1) - Min(A,A1));
if ([afFlag state] && Ranf()<0.5) A = -A;
if (B1 = [b1Flag state]) B = Min(B,B1) + Ranf()*(Max(B,B1) - Min(B,B1));
if ([bfFlag state] && Ranf()<0.5) B = -B;
if (C1 = [c1Flag state]) C = Min(C,C1) + Ranf()*(Max(C,C1) - Min(C,C1));
if ([cfFlag state] && Ranf()<0.5) C = -C;
if ([magFlag state]) Zf = (Function == Martin2) ? 4.0 : 1.0;
else Zf = [magField doubleValue];
if ([maxInFlag state]) mxp = (int) (0.40* (float)(W*H));
else mxp = [maxInRangePts intValue];
if ([maxTotFlag state]) mxP = 4 * mxp;
else mxP = [maxTotalPts intValue];
/* color processing */
if ([colFlag state]) nC = (mxP/Ncolors)/2;
else nC = [colInterval intValue];
}
nc = nC;
cx = W/2+moveX; cy = H/2+moveY;
[displaceX setIntValue:moveX];
[displaceY setIntValue:moveY];
[seedPertInt setIntValue:Pn];
[seedPertVal setDoubleValue:Pv];
[dynamFlush setIntValue:nD];
[funcButton setTitle:fname[Function]];
[hopAField setDoubleValue:A];
[hopBField setDoubleValue:B];
[hopCField setDoubleValue:C];
[magField setDoubleValue:Zf];
[maxInRangePts setIntValue:mxp];
[maxTotalPts setIntValue:mxP];
[colInterval setIntValue:nC];
return self;
}
- changeFunc:sender
{
char str[10];
Function = [sender selectedTag];
[funcAuto setState:NO];
sprintf(str,"%d", Function);
NXWriteDefault([NXApp appName], "MartinFunction", str);
[self newOne:sender];
return self;
}
- changeDynam:sender
{
nD = [sender intValue];
if ((nD <1) || (nD > MAXDYNAMPOINTS))
nD = MAXDYNAMPOINTS;
[dynamFlush setIntValue:nD];
[self makeNewDynam:nD];
[self newOne:sender];
return self;
}
/* We create the array of NXRects ahead of time so we do not waste time
building the array up as we go along */
- makeNewDynam:(int)num
{
NXRect *curr;
NXSize pixSize = {1,1};
if (pixels)
free(pixels);
pixels = (NXRect *)malloc(sizeof(NXRect)*(num+1));
for (curr = pixels; curr-pixels < num; ++curr)
curr->size = pixSize;
return self;
}
- setHopA:sender
{
if ([sender doubleValue] > 0) [aFlag setState:NO];
[self newOne:sender];
return self;
}
- setHopB:sender
{
if ([sender doubleValue] > 0) [bFlag setState:NO];
[self newOne:sender];
return self;
}
- setHopC:sender
{
if ([sender doubleValue] > 0) [cFlag setState:NO];
[self newOne:sender];
return self;
}
- setSeedInt:sender
{
if ([sender intValue] > 0) [seedIntFlag setState:NO];
[self newOne:sender];
return self;
}
- setMagnification:sender
{
if ([sender doubleValue] >= 0) [magFlag setState:NO];
[self newOne:sender];
return self;
}
- setSeedVal:sender
{
if ([sender doubleValue] >= 0) [seedValFlag setState:NO];
[self newOne:sender];
return self;
}
- setDisplacement:sender
{
moveX = [displaceX intValue];
moveY = [displaceY intValue];
[self newOne:sender];
return self;
}
- setColChange:sender
{
char str[30];
if ([sender intValue] > 0) {
[colFlag setState:NO];
sprintf(str,"%d", [sender intValue]);
NXWriteDefault([NXApp appName], "MartinColorInt", str);
}
[self newOne:sender];
return self;
}
- setMaxTot:sender
{
char str[30];
if ([sender intValue] > 0) {
[maxTotFlag setState:NO];
sprintf(str,"%d", [sender intValue]);
NXWriteDefault([NXApp appName], "MartinMaxTot", str);
}
[self newOne:sender];
return self;
}
- setMaxIn:sender
{
char str[30];
if ([sender intValue] > 0) {
[maxInFlag setState:NO];
sprintf(str,"%d", [sender intValue]);
NXWriteDefault([NXApp appName], "MartinMaxIn", str);
}
[self newOne:sender];
return self;
}
- setRandomColor:sender
{
char str[10];
Randomcolor = [sender state];
sprintf(str,"%d", Randomcolor);
NXWriteDefault([NXApp appName], "MartinRandomCol", str);
[self newOne:sender];
return self;
}
- changeColorMode:sender
{
int newColMode;
char str[10];
newColMode = [sender selectedTag];
if (Color != newColMode) {
Color = newColMode;
[self convertColors];
sprintf(str,"%d",Color);
NXWriteDefault([NXApp appName], "MartinColorMode", str);
}
[self newOne:self];
return self;
}
/* Weak way of changing from nonrandom color array to nonrandom gray array */
- convertColors
{
if (Color){
Ncolors = DEFAULTNUMCOLORS;
colors[0] = NX_COLORBLUE;
colors[1] = NX_COLORBROWN;
colors[2] = NX_COLORWHITE;
}
else{
Ncolors = 3;
colors[0] = NX_COLORWHITE;
colors[1] = NX_COLORDKGRAY;
colors[2] = NX_COLORLTGRAY;
}
return self;
}
/* Append the current fractal info (all of it) in the data file */
- remember:sender
{
NXStream *stream;
if (!(stream = NXMapFile(file, NX_WRITEONLY))) {
stream = NXOpenMemory(NULL, 0, NX_WRITEONLY);
}
NXSeek(stream, 0, NX_FROMEND);
NXPrintf(stream, "MartinView\n");
NXPrintf(stream, "%d %.15le\n",Pn,Pv);
NXPrintf(stream, "%d\n",Function);
NXPrintf(stream, "%.15le %.15le %.15le %.15le\n",A,B,C,Zf);
NXPrintf(stream, "%d %d %d\n",mxp,mxP,nC);
NXPrintf(stream, "%d %d\n",moveX,moveY);
NXSaveToFile(stream, file);
NXCloseMemory(stream, NX_FREEBUFFER);
return self;
}
- useFile:sender
{
NXStream *stream;
char name[15],str[10];
if ([sender state]) {
if (!(stream = NXMapFile(file, NX_READONLY))) {
[sender setState:NO];
streamPos = -1;
[self newOne:self];
}
else {
NXScanf(stream, "%s\n",name);
if (strcmp("MartinView",name)) {
[sender setState:NO];
streamPos = -1;
}
else streamPos = 0;
NXCloseMemory(stream, NX_FREEBUFFER);
[self newOne:self];
}
}
else {
streamPos = -1;
[self newOne:self];
}
sprintf(str,"%d",[sender state]);
NXWriteDefault([NXApp appName], "MartinUseFile", str);
return self;
}
- initFrame:(NXRect *)frameRect
{
[super initFrame:frameRect];
[self allocateGState]; // For faster lock/unlockFocus
strcpy(file,NXHomeDirectory());
strcat(file,fileName);
srandom(getpid());
isPaused = 0;
Ncolors = DEFAULTNUMCOLORS;
colors = (NXColor *)malloc(sizeof(NXColor)*Ncolors);
colors[0] = NX_COLORBLUE;
colors[1] = NX_COLORBROWN;
colors[2] = NX_COLORWHITE;
colors[3] = NX_COLORCYAN;
colors[4] = NXConvertRGBToColor(250,128, 114);
colors[5] = NX_COLORGRAY;
colors[6] = NX_COLORGREEN;
colors[7] = NXConvertRGBToColor(255,87, 33);
colors[8] = NX_COLORMAGENTA;
colors[9] = NX_COLORORANGE;
colors[10] = NX_COLORPURPLE;
colors[11] = NX_COLORRED;
colors[12] = NXConvertRGBToColor(227,207, 87);
colors[13] = NX_COLORYELLOW;
moveX = 0; moveY = 0;
Ranfseed=4326;
nD = STARTDYNAMPOINTS;
[self makeNewDynam:nD];
return self;
}
- inspectorWillBeRemoved
{
[myPrefPanel orderOut:self];
return self;
}
- inspector:sender
{
char buf[MAXPATHLEN];
int value;
if (!smallInspect)
{
sprintf(buf,"%s/MartinPrefs.nib",[sender moduleDirectory:"Martin"]);
[NXApp loadNibFile:buf owner:self withNames:NO];
Function=atoi(NXGetDefaultValue([NXApp appName], "MartinFunction"));
if (Function == -1)
[funcAuto setState:YES];
else {
[funcAuto setState:NO];
[funcButton setTitle:fname[Function]];
}
if ((value = atoi(NXGetDefaultValue([NXApp appName], "MartinMaxTot"))) == -1)
[maxTotFlag setState:YES];
else {
[maxTotFlag setState:NO];
[maxTotalPts setIntValue:value];
}
if ((value = atoi(NXGetDefaultValue([NXApp appName], "MartinMaxIn"))) == -1)
[maxInFlag setState:YES];
else {
[maxInFlag setState:NO];
[maxInRangePts setIntValue:value];
}
if ((value = atoi(NXGetDefaultValue([NXApp appName], "MartinColorInt"))) == -1)
[colFlag setState:YES];
else {
[colFlag setState:NO];
[colInterval setDoubleValue:value];
}
Randomcolor = atoi(NXGetDefaultValue([NXApp appName], "MartinRandomCol"));
[randomFlag setState:Randomcolor];
Color=atoi(NXGetDefaultValue([NXApp appName], "MartinColorMode"));
if (Color) [colorButton setTitle:"Color"];
else [colorButton setTitle:"Mono"];
[self convertColors];
currColor = (Randomcolor) ? ((Color) ? NXConvertRGBToColor(Ranf(), Ranf(), Ranf()) :
NXConvertGrayToColor(Ranf())) : colors[0];
[useFileFlag setState:atoi(NXGetDefaultValue([NXApp appName], "MartinUseFile"))];
if ([useFileFlag state])
[self useFile:useFileFlag];
else {
streamPos =-1;
[self newOne:self];
}
}
return smallInspect;
}
+ initialize
{
static NXDefaultsVector MartinViewDefaults = {{"MartinFunction", "-1"},
{"MartinMaxTot", "-1"},{"MartinMaxIn", "-1"},
{"MartinColorInt", "-1"},{"MartinRandomCol", "1"},{"MartinColorMode", "1"},
{"MartinUseFile", "0"},{NULL,NULL} };
NXRegisterDefaults([NXApp appName], MartinViewDefaults);
return self;
}
- sizeTo:(NXCoord)width :(NXCoord)height
{
[super sizeTo:width :height];
[self newOne:self];
return self;
}
- drawSelf:(const NXRect *)rects :(int)rectCount
{
if (!rects || !rectCount) return self;
PSsetgray(0.0);
NXRectFill(rects); // black screen
return self;
}
- free
{
if (pixels)
free(pixels);
if (Ncolors)
free(colors);
return [super free];
}
/* Why not a little fluff */
- windowWillMiniaturize:sender toMiniwindow:miniwindow
{
[sender setMiniwindowIcon:"MartinMini"];
return self;
}
- (BOOL) useBufferedWindow { return NO; }
- (const char *) windowTitle { return ( const char * ) "Martin Fractals";}
@end